package com.rimi.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chengliang
 */
public class JdbcUtil{

    private Connection connection;
    private PreparedStatement preparedStatement;
    private ResultSet resultSet;

    /**
     * 创建通道: 普通通道、预编译通道、存储过程通道
     * @param sql
     */
    private void createStatement(String sql) {
        connection = DruidUtil.getConnection();
        try {
            preparedStatement = connection.prepareStatement(sql);
        } catch (SQLException e) {
            System.out.println("创建预编译通道失败");
            e.printStackTrace();
        }
    }

    /**
     * 给预编译通道绑定参数的方法
     *
     * @param params 参数的数组
     */
    private void bundle(Object... params) {
        if (params == null) {
            return;
        }
        try {
            for (int i = 0; i < params.length; i++) {
                preparedStatement.setObject(i + 1, params[i]);
            }
        } catch (SQLException e) {
            System.out.println("绑定参数异常");
            e.printStackTrace();
        }
    }

    //执行sql语句 查询、修改
    //执行修改语句
    public boolean executeUpdateSql(String sql, Object... params) {
        createStatement(sql);
        //将参数绑定到sql的问号中
        bundle(params);
        //执行语句
        int i = 0;
        try {
            i = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            System.out.println("执行sql异常");
            e.printStackTrace();
        } finally {
            closeRes();
        }
        if (i > 0) {
            return true;
        }
        return false;
    }

    /**
     * 预编译通道执行查询语句
     * @param sql
     * @param params
     */
    public <T> List<T> executeQueryList(Class<T> tClass,String sql,Object... params){
         createStatement(sql);
         bundle(params);
         List<T> dataList=null;
        try {
            resultSet=preparedStatement.executeQuery();
            //获取所有列数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            while (resultSet.next()){
                if(dataList == null){
                    dataList = new ArrayList<T>();
                }
                //一条记录对应一个对象
                T object = tClass.newInstance();
                //遍历所有列: 列的起始位置从1开始
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    //java字段名
                    String javaPropertyName = changeColNameToJavaProperty(metaData.getColumnName(i));
                    //字段类型
                    Class<?> type = tClass.getDeclaredField(javaPropertyName).getType();
                    //字段对应的set方法名称
                    String setMethodName = changePropertyNameToSetMethodName(javaPropertyName);
                    // 通过set方法名称与参数类型 ，获取对象中的set方法
                    Method setMethod = tClass.getDeclaredMethod(setMethodName,type);
                    //调用set方法
                    setMethod.invoke(object,resultSet.getObject(i));
                }
                //循环结束后对象的所有的字段都被赋值，将对象存储到集合中
                dataList.add(object);
            }
            //jdbc 离线结果集
            return dataList;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            closeRes();
        }
        return null;
    }

    public int executeQueryCount(String sql,Object... params){
        createStatement(sql);
        bundle(params);
        try {
            resultSet=preparedStatement.executeQuery();
            if(resultSet.next()){
                return resultSet.getInt(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }


    /**
     * 预编译通道执行查询语句
     * @param sql
     * @param params
     */
    public <T> T executeQueryObject(Class<T> tClass,String sql,Object... params){
        createStatement(sql);
        bundle(params);
        try {
            resultSet=preparedStatement.executeQuery();
            //获取所有列数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            if (resultSet.next()){
                //一条记录对应一个对象
                T object = tClass.newInstance();
                //遍历所有列: 列的起始位置从1开始
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    //java字段名 user_name --> userName
                    String javaPropertyName = changeColNameToJavaProperty(metaData.getColumnName(i));
                    //字段类型 String
                    Class<?> type = tClass.getDeclaredField(javaPropertyName).getType();
                    //字段对应的set方法名称 setUserName
                    String setMethodName = changePropertyNameToSetMethodName(javaPropertyName);
                    // 通过set方法名称与参数类型 ，获取对象中的set方法
                    Method setMethod = tClass.getDeclaredMethod(setMethodName,type);
                    //调用set方法
                    setMethod.invoke(object,resultSet.getObject(i));
                }
                //循环结束后对象的所有的字段都被赋值，将对象存储到集合中
                return object;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            closeRes();
        }
        return null;
    }

    /**
     * 关闭资源
     */
    public void closeRes() {
        try {
            if(resultSet != null){
                resultSet.close();
            }
            if (preparedStatement != null) {
                preparedStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    /**
     * 由于数据库中的命名规则大多是下划线，所以创建一个将下划线转为驼峰规则的命名
     * @param sql
     * @return	返回字段的名称
     */
    private static String changeColNameToJavaProperty(String sql) {
        // 以下划线将其分割成多个单词
        String[] words = sql.split("_");
        StringBuffer buffer = new StringBuffer();
        // 第一个单词首字母小写，保证一定有一个
        buffer.append(words[0]);
        for(int index = 1; index < words.length; index++) {
            // subString取子字符串，(a,b), 从下标为a开始，到下标为b结束，包括a的字符，不包括b字符,如果b不存在，一致读到最后一个字符
            buffer.append(words[index].substring(0, 1).toUpperCase());
            buffer.append(words[index].substring(1));
        }
        return buffer.toString();
    }

    /**
     * 获取set方法名称
     * @param sql
     * @return
     */
    private static  String getSetMethodName(String sql){
        //获取Java驼峰式 名称
        String javaPropertyName = changeColNameToJavaProperty(sql);
        return changePropertyNameToSetMethodName(javaPropertyName);
    }

    /**
     * 将javaPropertyName转换为对应的set方法名称
     * @return
     */
    private static  String changePropertyNameToSetMethodName(String javaPropertyName){
        StringBuffer stringBuffer = new StringBuffer();
        //set开头
        stringBuffer.append("set");
        //将首字符大写
        stringBuffer.append(javaPropertyName.substring(0,1).toUpperCase());
        //将剩余的内容拼接
        stringBuffer.append(javaPropertyName.substring(1));
        return stringBuffer.toString();
    }

}
